package com.ilink.groundservice.service.impl.AiX;/**
 * <h3>iLink-java-backend-zhangbo2</h3>
 *
 * @Description <p>专区实现类</p>
 * @Author ZhangBo
 * @Date 2025-01-17 11:48
 **/

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ilink.groundservice.entity.PO.AiX.AiXArea;
import com.ilink.groundservice.entity.PO.AiX.AiXDelete;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneAuthor;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneBase;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneBeginEnd;
import com.ilink.groundservice.entity.PO.AiX.AiXScenePhaseBase;
import com.ilink.groundservice.entity.PO.AiX.AiXScenePhaseFinish;
import com.ilink.groundservice.entity.PO.AiX.AiXScenePhaseOpus;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneSignUp;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneStartLearn;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneSubPhase;
import com.ilink.groundservice.entity.PO.AiX.AiXSceneSubPhaseOpus;
import com.ilink.groundservice.entity.PO.AiX.AiXSubPhaseResource;
import com.ilink.groundservice.entity.PO.AiX.AiXTag;
import com.ilink.groundservice.entity.PO.AiX.AiXTagConnect;
import com.ilink.groundservice.entity.VO.AiX.AiXAreaResponse;
import com.ilink.groundservice.entity.VO.AiX.AiXAreaSceneInfo;
import com.ilink.groundservice.entity.VO.AiX.AiXSignUpResponse;
import com.ilink.groundservice.entity.VO.AiX.UserPermissionResponse;
import com.ilink.groundservice.entity.VO.AiX.AiXUserScoreResponse;
import com.ilink.groundservice.mapper.AiX.AiXAreaMapper;
import com.ilink.groundservice.mapper.AiX.AiXDeleteMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneAuthorMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneBaseMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneBeginEndMapper;
import com.ilink.groundservice.mapper.AiX.AiXScenePhaseBaseMapper;
import com.ilink.groundservice.mapper.AiX.AiXScenePhaseFinishMapper;
import com.ilink.groundservice.mapper.AiX.AiXScenePhaseOpusMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneSignUpMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneStartLearnMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneSubPhaseMapper;
import com.ilink.groundservice.mapper.AiX.AiXSceneSubPhaseOpusMapper;
import com.ilink.groundservice.mapper.AiX.AiXSubPhaseResourceMapper;
import com.ilink.groundservice.mapper.AiX.AiXTagConnectMapper;
import com.ilink.groundservice.mapper.AiX.AiXTagMapper;
import com.ilink.groundservice.service.AiX.AiXActivityService;
import com.ilink.groundservice.service.AiX.AiXAreaService;
import com.ilink.ilinkapi.client.UserServiceClient;
import com.ilink.ilinkapi.dto.ground.AiX.AiXAreaInsertRequset;
import com.ilink.ilinkapi.dto.ground.AiX.AiXAreaUpdateRequest;
import com.ilink.ilinkcommon.domain.R;
import com.ilink.ilinkcommon.domain.User;
import com.ilink.ilinkcommon.service.oss.MinioService;
import com.ilink.ilinkcommon.utils.BeanUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import com.ilink.ilinkcommon.utils.SnowflakeIdGenerator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

/**
 * @ClassName AiXAreaServiceImpl
 * @Description TODO
 * @Author ZhangBo
 * @Date 2025-01-17 11:48
 **/
@Service
@Slf4j
@RequiredArgsConstructor
public class AiXAreaServiceImpl implements AiXAreaService {
    private final AiXSceneBaseMapper aiXSceneBaseMapper;
    private final AiXSceneAuthorMapper aiXSceneAuthorMapper;
    private final UserServiceClient userServiceClient;

    private final AiXSceneBeginEndMapper aiXSceneBeginEndMapper;
    private final AiXSceneStartLearnMapper aiXSceneStartLearnMapper;
    private final AiXSceneSignUpMapper aiXSceneSignUpMapper;

    private final AiXScenePhaseBaseMapper aiXScenePhaseBaseMapper;
    private final AiXSceneSubPhaseMapper aiXSceneSubPhaseMapper;
    private final AiXScenePhaseFinishMapper aiXScenePhaseFinishMapper;
    private final AiXScenePhaseOpusMapper aiXScenePhaseOpusMapper;
    private final AiXSceneSubPhaseOpusMapper aiXSceneSubPhaseOpusMapper;

    private final AiXAreaMapper aiXAreaMapper;
    private final MinioService minioService;
    private final AiXTagMapper aiXTagMapper;
    private final AiXTagConnectMapper aiXTagConnectMapper;

    private final AiXSubPhaseResourceMapper subPhaseResourceMapper;
    private final AiXScenePhaseOpusMapper scenePhaseOpusMapper;
    private final AiXSceneSubPhaseOpusMapper sceneSubPhaseOpusMapper;
    private final AiXTagConnectMapper tagConnectMapper;
    private final AiXTagMapper tagMapper;

    private final AiXDeleteMapper aiXDeleteMapper;

    /**
     * @Author ZhangBo
     * @Description 每24小时执行一次清理任务
     * @Date 11:03 2025/1/21
     * @Param []
     * @return void
     **/
    @Scheduled(fixedRate = 24 * 60 * 60 * 1000)
    public void deleteMinio() {
        log.info("开始执行定时MinIO清理任务");
        try {
            deleteMinIOFile();
            log.info("完成MinIO清理任务");
        } catch (Exception e) {
            log.error("执行MinIO清理任务时发生错误", e);
        }
    }

    @Override
    public UserPermissionResponse checkUserPermissions(Long sceneId, String userId) {
        UserPermissionResponse response = new UserPermissionResponse();
        response.setCreate(false);
        response.setView(false);
        response.setEdit(false);

        // 判断是否是教师
        boolean isTeacher = isTeacher(userId);
        response.setCreate(isTeacher);  // 只有教师可以创建

        if(sceneId != 0L){
            // 判断是否是超级管理员
            boolean isSuperAdmin = isSuperAdmin(userId);
            // 判断是否是出品人
            boolean isAuthor = isAuthor(sceneId, userId);
            // 超级管理员和出品人始终具有查看、编辑和创建权限
            if (isSuperAdmin || isAuthor) {
                response.setView(true);   // 超级管理员和出品人可以查看
                response.setEdit(true);   // 超级管理员和出品人可以编辑
            }

            boolean isPublish = isScenePublished(sceneId);
            if (isPublish) {
                response.setView(true);   // 如果场景已发布，所有人可以查看
            }
        }

        return response;
    }

    @Override
    public List<User> getAllSceneAuthors(Long areaId) {
        // 获取专区内所有场景
        List<AiXSceneBase> sceneBases = aiXSceneBaseMapper.selectList(
            new LambdaQueryWrapper<AiXSceneBase>().eq(AiXSceneBase::getAreaId, areaId)
        );
        // 根据所有场景的sceneId查询出品人信息
        List<AiXSceneAuthor> sceneAuthors = aiXSceneAuthorMapper.selectList(
            new LambdaQueryWrapper<AiXSceneAuthor>().in(AiXSceneAuthor::getSceneId, 
                sceneBases.stream().map(AiXSceneBase::getSceneId).collect(Collectors.toList()))
        );
        // 根据author中记录的userid查询user全部信息
        List<User> users = sceneAuthors.stream()
            .map(author -> getUserInfo(author.getUserId()))
            .collect(Collectors.toList());
        return users;
    }

    @Override
    public List<AiXAreaSceneInfo> getSceneAuthorInfo(Long areaId) {
        // 获取每一个微场景的出品人的对应信息
        List<AiXSceneBase> sceneBases = aiXSceneBaseMapper.selectList(
            new LambdaQueryWrapper<AiXSceneBase>().eq(AiXSceneBase::getAreaId, areaId)
        );
        
        // 根据sceneId查询出品人信息
        List<AiXSceneAuthor> sceneAuthors = aiXSceneAuthorMapper.selectList(
            new LambdaQueryWrapper<AiXSceneAuthor>().in(AiXSceneAuthor::getSceneId, 
                sceneBases.stream().map(AiXSceneBase::getSceneId).collect(Collectors.toList()))
        );
        
        // 将sceneAuthors和sceneBases进行匹配，返回AiXAreaSceneInfo
        List<AiXAreaSceneInfo> sceneInfos = sceneAuthors.stream()
            .map(author -> {
                AiXAreaSceneInfo info = new AiXAreaSceneInfo();
                info.setSceneId(author.getSceneId());
                
                // 设置场景名称
                info.setSceneName(sceneBases.stream()
                    .filter(scene -> scene.getSceneId().equals(author.getSceneId()))
                    .map(AiXSceneBase::getSceneTitle)
                    .findFirst()
                    .orElse(null));
                    
                // 获取用户信息并设置
                User userDetail = getUserInfo(author.getUserId());
                if (userDetail != null) {
                    info.setUserId(userDetail.getUserId());
                    info.setUserName(userDetail.getRealname());
                    info.setUserImageUrl(userDetail.getUserImage());
                    info.setUserCollege(userDetail.getUserCollege());
                }
                
                // 获取最新的开课记录时间
                AiXSceneBeginEnd latestBeginEnd = aiXSceneBeginEndMapper.selectOne(
                    new LambdaQueryWrapper<AiXSceneBeginEnd>()
                        .eq(AiXSceneBeginEnd::getSceneId, author.getSceneId())
                        .orderByDesc(AiXSceneBeginEnd::getRecordNumber)
                        .last("LIMIT 1")
                );
                
                if (latestBeginEnd != null) {
                    info.setUpdatedTime(latestBeginEnd.getStartTime());
                }
                
                return info;
            })
            .collect(Collectors.toList());
        // 按照修改时间倒序排列
        sceneInfos.sort(Comparator.comparing(AiXAreaSceneInfo::getUpdatedTime,
                Comparator.nullsLast(Comparator.reverseOrder())));
        return sceneInfos;
    }

    // 统计某用户专区下的所有微场景下所有阶段下的作业分数和
    @Override
    public R getPhaseWorkScoreSum(String userId, Long areaId) {
        try {
            // 1. 先查询该专区下的所有场景
            List<AiXSceneBase> sceneList = aiXSceneBaseMapper.selectList(
                new LambdaQueryWrapper<AiXSceneBase>()
                    .eq(AiXSceneBase::getAreaId, areaId)
            );

            // 如果没有场景,返回0
            if (sceneList == null || sceneList.isEmpty()) {
                return R.ok("统计作业分数和成功", 0);
            }

            // 2. 获取所有场景ID
            List<Long> sceneIds = sceneList.stream()
                .map(AiXSceneBase::getSceneId)
                .collect(Collectors.toList());

            // 3. 查询这些场景下的所有有作业的阶段
            List<AiXScenePhaseBase> phaseList = aiXScenePhaseBaseMapper.selectList(
                new LambdaQueryWrapper<AiXScenePhaseBase>()
                    .in(AiXScenePhaseBase::getSceneId, sceneIds)
                    .eq(AiXScenePhaseBase::getWorkExist, true)  // 只查询有作业的阶段
            );

            int phaseOpusScore = 0;
            if (!phaseList.isEmpty()) {
                // 4. 获取所有阶段ID
                List<Long> phaseIds = phaseList.stream()
                    .map(AiXScenePhaseBase::getPhaseId)
                    .collect(Collectors.toList());

                // 5. 先从AiXScenePhaseFinish表中找到该用户已完成的阶段ID
                List<Long> finishedPhaseIds = aiXScenePhaseFinishMapper.selectList(
                        new LambdaQueryWrapper<AiXScenePhaseFinish>()
                            .in(AiXScenePhaseFinish::getPhaseId, phaseIds)
                            .eq(AiXScenePhaseFinish::getUserId, userId)
                            .eq(AiXScenePhaseFinish::getIsFinish, true)
                    ).stream()
                    .map(AiXScenePhaseFinish::getPhaseId)
                    .collect(Collectors.toList());

                // 6. 统计该用户在这些已完成阶段中获得的实际分数总和
                if (!finishedPhaseIds.isEmpty()) {
                    phaseOpusScore = aiXScenePhaseOpusMapper.selectList(
                            new LambdaQueryWrapper<AiXScenePhaseOpus>()
                                .eq(AiXScenePhaseOpus::getUserId, userId)
                        ).stream()
                        .mapToInt(AiXScenePhaseOpus::getScore)
                        .sum();
                }
            }
            // 7. 查询这些阶段下的所有有作业的子阶段
            List<AiXSceneSubPhase> subPhaseList = new ArrayList<>();
            if (!phaseList.isEmpty()) {
                List<Long> phaseIds = phaseList.stream()
                    .map(AiXScenePhaseBase::getPhaseId)
                    .collect(Collectors.toList());

                subPhaseList = aiXSceneSubPhaseMapper.selectList(
                    new LambdaQueryWrapper<AiXSceneSubPhase>()
                        .in(AiXSceneSubPhase::getPhaseId, phaseIds)
                        .gt(AiXSceneSubPhase::getWorkExist, true)  // 只查询有作业分数的子阶段
                );
            }

            Integer subPhaseOpusScore = 0;
            if (!subPhaseList.isEmpty()) {
                // 8. 获取所有子阶段ID
                List<Long> subPhaseIds = subPhaseList.stream()
                    .map(AiXSceneSubPhase::getSubPhaseId)
                    .collect(Collectors.toList());

                // 9. 统计该用户在这些子阶段中获得的实际分数总和
                subPhaseOpusScore = aiXSceneSubPhaseOpusMapper.selectList(
                        new LambdaQueryWrapper<AiXSceneSubPhaseOpus>()
                            .in(AiXSceneSubPhaseOpus::getSubPhaseId, subPhaseIds)
                            .eq(AiXSceneSubPhaseOpus::getUserId, userId)
                    ).stream()
                    .mapToInt(AiXSceneSubPhaseOpus::getScore)
                    .sum();
            }

            // 10. 返回阶段和子阶段分数之和
            Integer totalScore = phaseOpusScore + subPhaseOpusScore;
            return R.ok("统计作业分数和成功", totalScore);

        } catch (Exception e) {
            log.error("统计作业分数和失败，userId: " + userId + ", areaId: " + areaId, e);
            return R.error("统计作业分数和失败");
        }
    }

    // 对专区下所有用户的作业分数进行排序
    @Override
    public R getAreaWorkScoreSort(Long areaId, Long num) {
        try {
            // 1. 获取该专区下所有场景的ID
            List<Long> sceneIds = aiXSceneBaseMapper.selectList(
                new LambdaQueryWrapper<AiXSceneBase>()
                    .eq(AiXSceneBase::getAreaId, areaId)
            ).stream()
            .map(AiXSceneBase::getSceneId)
            .collect(Collectors.toList());

            // 2. 根据场景ID获取所有的开始学习记录的 beginEndId
            List<Long> beginEndIds = aiXSceneBeginEndMapper.selectList(
                new LambdaQueryWrapper<AiXSceneBeginEnd>()
                    .in(AiXSceneBeginEnd::getSceneId, sceneIds)
            ).stream()
            .map(AiXSceneBeginEnd::getBeginEndId)
            .collect(Collectors.toList());

            // 3. 获取该专区所有开始学习的用户
            List<AiXSceneStartLearn> startLearnList = aiXSceneStartLearnMapper.selectList(
                new LambdaQueryWrapper<AiXSceneStartLearn>()
                    .in(AiXSceneStartLearn::getBeginEndId, beginEndIds) // 根据获取的 beginEndId 查询
                    .eq(AiXSceneStartLearn::getIsSignUp, 1) // 只查询已报名的用户
            );

            // 4. 统计每个用户的分数
            Map<String, Integer> userScores = new HashMap<>();
            for (AiXSceneStartLearn startLearn : startLearnList) {
                String userId = startLearn.getUserId();
                Integer phaseOpusScore = aiXScenePhaseOpusMapper.selectList(
                    new LambdaQueryWrapper<AiXScenePhaseOpus>()
                        .eq(AiXScenePhaseOpus::getUserId, userId)
                ).stream()
                .mapToInt(AiXScenePhaseOpus::getScore)
                .sum();

                Integer subPhaseOpusScore = aiXSceneSubPhaseOpusMapper.selectList(
                    new LambdaQueryWrapper<AiXSceneSubPhaseOpus>()
                        .eq(AiXSceneSubPhaseOpus::getUserId, userId)
                ).stream()
                .mapToInt(AiXSceneSubPhaseOpus::getScore)
                .sum();

                // 5. 计算总分
                Integer totalScore = phaseOpusScore + subPhaseOpusScore;
                userScores.put(userId, totalScore);
            }

            // 6. 对用户分数进行排序
            List<Map.Entry<String, Integer>> sortedScores = userScores.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByValue(Collections.reverseOrder()))
                .limit(num != null && num > 0 ? num : Long.MAX_VALUE)
                .collect(Collectors.toList());

            // 7. 构建返回的用户和分数列表
            List<AiXUserScoreResponse> result = new ArrayList<>();
            for (Map.Entry<String, Integer> entry : sortedScores) {
                User user = getUserInfo(entry.getKey());
                AiXUserScoreResponse response = new AiXUserScoreResponse();
                response.setUser(user);
                response.setScore(entry.getValue());
                result.add(response);
            }

            return R.ok("统计专区所有用户分数成功", result);
        } catch (Exception e) {
            log.error("统计专区所有用户分数失败，areaId: " + areaId, e);
            return R.error("统计专区所有用户分数失败");
        }
    }

    // 对专区下的所有报名记录进行排序，时间越晚，排名越靠前
    @Override
    public R getAreaSignUpSort(Long areaId, Long num) {
        try {
            // 1. 获取专区下所有的场景
            List<AiXSceneBase> scenes = aiXSceneBaseMapper.selectList(
                new LambdaQueryWrapper<AiXSceneBase>()
                    .eq(AiXSceneBase::getAreaId, areaId)
            );

            // 2. 获取这些场景的所有开课记录ID
            List<Long> sceneIds = scenes.stream()
                .map(AiXSceneBase::getSceneId)
                .collect(Collectors.toList());

            List<AiXSceneBeginEnd> beginEnds = aiXSceneBeginEndMapper.selectList(
                new LambdaQueryWrapper<AiXSceneBeginEnd>()
                    .in(AiXSceneBeginEnd::getSceneId, sceneIds)
            );

            List<Long> beginEndIds = beginEnds.stream()
                .map(AiXSceneBeginEnd::getBeginEndId)
                .collect(Collectors.toList());

            // 3. 获取所有报名记录并按时间倒序排序，限制返回记录数
            List<AiXSceneSignUp> signUps = aiXSceneSignUpMapper.selectList(
                new LambdaQueryWrapper<AiXSceneSignUp>()
                    .in(AiXSceneSignUp::getBeginEndId, beginEndIds)
                    .orderByDesc(AiXSceneSignUp::getStartTime)
                    .last(num != null && num > 0, "LIMIT " + num)
            );

            // 4. 构建返回结果
            List<AiXSignUpResponse> result = new ArrayList<>();
            for (AiXSceneSignUp signUp : signUps) {
                AiXSignUpResponse response = new AiXSignUpResponse();
                
                // 获取用户信息
                response.setUser(getUserInfo(signUp.getUserId()));
                
                // 获取开课记录对应的场景信息
                AiXSceneBeginEnd beginEnd = beginEnds.stream()
                    .filter(be -> be.getBeginEndId().equals(signUp.getBeginEndId()))
                    .findFirst()
                    .orElse(null);
                
                if (beginEnd != null) {
                    Long sceneId = beginEnd.getSceneId();
                    response.setSceneId(sceneId);
                    
                    // 获取场景标题
                    AiXSceneBase scene = scenes.stream()
                        .filter(s -> s.getSceneId().equals(sceneId))
                        .findFirst()
                        .orElse(null);
                    
                    if (scene != null) {
                        response.setSceneTitle(scene.getSceneTitle());
                    }
                }
                
                response.setStartTime(signUp.getStartTime());
                result.add(response);
            }

            return R.ok("获取专区报名排序成功", result);
        } catch (Exception e) {
            log.error("获取专区报名排序失败，areaId: " + areaId, e);
            return R.error("获取专区报名排序失败");
        }
    }

    @Override
    @Transactional
    public R insertArea(AiXAreaInsertRequset requset){
        SnowflakeIdGenerator idGenerator = new SnowflakeIdGenerator(1, 1);
        Long areaId = idGenerator.nextId();
        AiXArea area = new AiXArea();
        area.setAreaId(areaId);
        area.setAreaName(requset.getAreaName());
        area.setIntroduction(requset.getIntroduction());
        String objectName = "area/"+areaId+ getFileExtension(requset.getCoverImage().getOriginalFilename());
        boolean isUploaded = minioService.uploadBucketFile(requset.getCoverImage(), "dataset-square-migrate", objectName);
        if (!isUploaded) {
            return R.error("专区封面上传失败");
        }
        area.setCoverUrl(objectName);
        aiXAreaMapper.insert(area);
        if (requset.getTags() != null) {
            handleTags(requset.getTags(), areaId);
        }
        return R.ok("专区插入成功");
    }

    @Override
    @Transactional
    public R updateAreaBase(AiXAreaUpdateRequest request){
        Long areaId = request.getAreaId();
        AiXArea area = new AiXArea();
        area.setAreaId(areaId);
        area.setAreaName(request.getAreaName());
        area.setIntroduction(request.getIntroduction());
        aiXAreaMapper.updateById(area);
        aiXTagConnectMapper.delete(new LambdaQueryWrapper<AiXTagConnect>()
                .eq(AiXTagConnect::getConnectTableKey, areaId)
                .eq(AiXTagConnect::getConnectTable, "ai_x_area"));
        if (request.getTags() != null) {
            handleTags(request.getTags(), areaId); // 调用提取的标签处理方法
        }
        return R.ok("专区更新成功");
    }
    @Override
    @Transactional
    public R updateAreaCover(MultipartFile file, Long areaId){
        String objectName = "area/" + areaId + getFileExtension(file.getOriginalFilename());
        boolean isUploaded = minioService.uploadBucketFile(file, "dataset-square-migrate", objectName);
        if (!isUploaded) {
            return R.error("专区封面更新失败");
        }
        AiXArea area = aiXAreaMapper.selectById(areaId);
        if (area == null) {
            return R.error("专区未找到");
        }
        area.setCoverUrl(objectName);
        aiXAreaMapper.updateById(area);
        return R.ok("专区封面更新成功");

    }

    @Override
    public AiXAreaResponse getArea(Long areaId){
        AiXArea area = aiXAreaMapper.selectById(areaId);
        List<AiXTagConnect> tagConnects = aiXTagConnectMapper.selectList(
                new LambdaQueryWrapper<AiXTagConnect>()
                        .eq(AiXTagConnect::getConnectTableKey, areaId)
                        .eq(AiXTagConnect::getConnectTable, "ai_x_area")
        );
        List<AiXTag> tags = tagConnects.stream()
                .map(tagConnect -> aiXTagMapper.selectById(tagConnect.getTagId()))
                .collect(Collectors.toList());
        String imagePath = minioService.getBucketFileUrl("dataset-square-migrate",area.getCoverUrl());
        if(imagePath == null){
            log.error("专区封面未找到"+area.getCoverUrl());
            return null;
        }
        AiXAreaResponse response = new AiXAreaResponse();
        response.setAreaId(areaId);
        response.setAreaTitle(area.getAreaName());
        response.setIntroduction(area.getIntroduction());
        response.setCoverUrl(imagePath);
        response.setTags(tags.stream().map(AiXTag::getTagName).collect(Collectors.toList()));
        return response;
    }

    @Override
    public List<String> getAreaTags(Long areaId) {
        return aiXTagConnectMapper.getAreaTags(areaId, 12);
    }

    // 判断是否是教师
    private boolean isTeacher(String userId) {
        R whoami = userServiceClient.whoami(userId);
        HttpStatus status = HttpStatus.valueOf(whoami.getCode());
        if (!status.is2xxSuccessful()) {
            log.error(String.format("获取用户信息失败，用户ID: %s", userId));
            return false;
        }

        User userDetail = BeanUtils.copyBean(whoami.getData(), User.class);
        String userType = userDetail.getUserType();
        return Arrays.asList("BIAdmin", "L0101", "L0107", "L0108", "L0109").contains(userType);
    }

    // 判断是否是超级管理员
    private boolean isSuperAdmin(String userId) {
        R whoami = userServiceClient.whoami(userId);
        HttpStatus status = HttpStatus.valueOf(whoami.getCode());
        if (!status.is2xxSuccessful()) {
            log.error(String.format("获取用户信息失败，用户ID: %s", userId));
            return false;
        }

        User userDetail = BeanUtils.copyBean(whoami.getData(), User.class);
        String userType = userDetail.getUserType();
        return "BIAdmin".equals(userType);
    }

    // 判断是否是该场景的出品人
    private boolean isAuthor(Long sceneId, String userId) {
        List<String> userIds = getUserIdsBySceneId(sceneId);
        return userIds != null && userIds.contains(userId);
    }

    // 获取场景所有出品人ID
    private List<String> getUserIdsBySceneId(Long sceneId) {
        List<AiXSceneAuthor> sceneAuthors = aiXSceneAuthorMapper.selectList(
            new LambdaQueryWrapper<AiXSceneAuthor>().eq(AiXSceneAuthor::getSceneId, sceneId)
        );

        if (sceneAuthors == null) {
            return null;
        }

        return sceneAuthors.stream()
            .map(AiXSceneAuthor::getUserId)
            .collect(Collectors.toList());
    }

    /**
     * @Author ZhangBo
     * @Description 检查场景的发布状态
     * @Date 14:54 2025/1/17
     * @Param [sceneId]
     * @return boolean
     **/
    private boolean isScenePublished(Long sceneId) {
        AiXSceneBase scene = aiXSceneBaseMapper.selectById(sceneId);
        return Boolean.TRUE.equals(scene.getIsPublish());  // 检查 isPublish 字段
    }

    private User getUserInfo(String userId) {
        R whoami = userServiceClient.whoami(userId);
        HttpStatus status = HttpStatus.valueOf(whoami.getCode());
        if (!status.is2xxSuccessful()) {
            log.error(String.format("获取用户信息失败，用户ID: %s", userId));
            return null;
        }
        User userDetail = BeanUtils.copyBean(whoami.getData(), User.class);
        return userDetail;
    }

    // 定期删除标签
    @Scheduled(fixedRate = 24 * 60 * 60 * 1000)
    public void cleanInvalidTagConnections() {
        // 获取各表的有效主键
        List<Long> resourceIds = subPhaseResourceMapper.selectList(null)
            .stream()
            .map(AiXSubPhaseResource::getResourceId)
            .collect(Collectors.toList());

        List<Long> phaseOpusIds = scenePhaseOpusMapper.selectList(null)
            .stream()
            .map(AiXScenePhaseOpus::getPhaseOpusId)
            .collect(Collectors.toList());

        List<Long> subPhaseOpusIds = sceneSubPhaseOpusMapper.selectList(null)
            .stream()
            .map(AiXSceneSubPhaseOpus::getSubPhaseOpusId)
            .collect(Collectors.toList());

        // 清理ai_x_sub_phase_resource相关的无效标签
        cleanInvalidConnections("ai_x_sub_phase_resource", resourceIds);

        // 清理ai_x_scene_phase_opus相关的无效标签
        cleanInvalidConnections("ai_x_scene_phase_opus", phaseOpusIds);

        // 清理ai_x_scene_sub_phase_opus相关的无效标签
        cleanInvalidConnections("ai_x_scene_sub_phase_opus", subPhaseOpusIds);

        checkAndDeleteUnusedTags();

    }

    public void cleanInvalidConnections(String tableName, List<Long> validIds) {
        LambdaQueryWrapper<AiXTagConnect> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AiXTagConnect::getConnectTable, tableName);

        List<AiXTagConnect> deletedEntries = tagConnectMapper.selectList(wrapper);

        if (validIds.isEmpty()) {
            // 如果没有有效ID，删除该表所有关联
            tagConnectMapper.delete(wrapper);
            log.info("已删除表中的所有连接: {}", tableName);
            return;
        }
        wrapper.notIn(AiXTagConnect::getConnectTableKey, validIds);
        tagConnectMapper.delete(wrapper);

        log.info("已删除表中无效ID的连接: {}，无效ID: {}", tableName, deletedEntries);
    }

    public void checkAndDeleteUnusedTags() {
        LambdaQueryWrapper<AiXTag> wrapper = new LambdaQueryWrapper<>();
        List<Long> unusedTagIds = tagMapper.selectList(null).stream()
            .map(AiXTag::getTagId)
            .filter(tagId -> tagConnectMapper.selectList(null).stream()
                .map(AiXTagConnect::getTagId)
                .collect(Collectors.toList()).contains(tagId) == false)
            .collect(Collectors.toList());

        if (!unusedTagIds.isEmpty()) {
            log.info("正在删除未使用的标签，ID: {}", unusedTagIds);
            wrapper.in(AiXTag::getTagId, unusedTagIds);
            tagMapper.delete(wrapper);
        }
    }

    private String getFileExtension(String fileName) {
        if (fileName == null) {
            return "";
        }
        int dotIndex = fileName.lastIndexOf('.');
        return dotIndex == -1 ? "" : fileName.substring(dotIndex);
    }
    private void handleTags(List<String> tags, Long areaId) {
        for (String tag : tags) {
            // 检查标签是否已存在
            AiXTag existingTag = aiXTagMapper.selectOne(new LambdaQueryWrapper<AiXTag>().eq(AiXTag::getTagName, tag).last("LIMIT 1"));
            Long tagId;
            if (existingTag == null) {
                // 标签不存在，生成随机ID并插入新标签
                tagId = new SnowflakeIdGenerator(1, 1).nextId();
                AiXTag newTag = new AiXTag();
                newTag.setTagId(tagId);
                newTag.setTagName(tag);
                aiXTagMapper.insert(newTag); // 插入新标签
            } else {
                // 标签已存在，使用现有的tagId
                tagId = existingTag.getTagId();
            }

            // 在连接表中插入关联
            AiXTagConnect tagConnect = new AiXTagConnect();
            tagConnect.setConnectId(new SnowflakeIdGenerator(1, 1).nextId()); // 生成连接表主键
            tagConnect.setConnectTable("ai_x_area");
            tagConnect.setConnectTableKey(areaId);
            tagConnect.setTagId(tagId);
            aiXTagConnectMapper.insert(tagConnect); // 插入关联
        }
    }
    // 根据AiXDelete表删除minIO中的文件，删除路径为deletePath
    // 再删除AiXDelete表中的记录
    private void deleteMinIOFile() {
        // 循环删除AiXDelete表中的记录  
        List<AiXDelete> deleteRecords = aiXDeleteMapper.selectList(null);
        if (deleteRecords != null && !deleteRecords.isEmpty()) {
            for (AiXDelete deleteRecord : deleteRecords) {
                log.info("定时删除");
                log.info(String.valueOf(deleteRecord));
                try {
                    minioService.deleteDirectory("dataset-square-migrate", deleteRecord.getDeletePath()+"/");
                } catch (Exception e) {
                    log.error("删除MinIO文件失败，路径: " + deleteRecord.getDeletePath(), e);
                    // 如果MinIO删除失败，继续执行删除AiXDelete记录
                }
                aiXDeleteMapper.deleteById(deleteRecord.getDeleteId());
            }
        }
    }

    @Override
    public List<AiXArea> getAreaList() {
        return aiXAreaMapper.selectList(null);
    }
}
